package cn.itcast.cloud.storage;

import com.aliyun.oss.OSSClient;
import com.aliyun.oss.common.utils.IOUtils;
import com.aliyun.oss.internal.OSSUtils;
import com.aliyun.oss.model.AppendObjectRequest;
import com.aliyun.oss.model.AppendObjectResult;
import com.aliyun.oss.model.OSSObject;
import com.aliyun.oss.model.UploadFileRequest;
import org.junit.Assert;
import org.junit.Test;

import java.io.ByteArrayInputStream;
import java.io.InputStream;

/**
 * 上传下载CRC校验
 */
public class CRCSample {
    private static String endpoint = "http://oss-cn-zhangjiakou.aliyuncs.com";
    private static String accessKeyId = "LTAIXeZktAHXvAgc";
    private static String accessKeySecret = "iHpKZJ5KiB7imcohA7VgjDzLY2O87w";
    private static String bucketName = "jiaze";
    private static String uploadFile = "<uploadFile>";
    private static String key = "crc-sample.txt";

    @Test
    public void testCRC() throws Throwable {
        String content = "Hello OSS, Hi OSS, OSS OK.";

        // CRC check is enabled by default for upload or download. To turn it off, use the commented code below.
        // ClientConfiguration config = new ClientConfiguration();
        // config.setCrcCheckEnabled(false);
        // OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
        OSSClient ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);

        // putObject/uploadPart/uploadFile are automatically enabled with CRC.
        // However, appendObject needs to call AppendObjectRequest.setInitCRC to enable CRC.
        ossClient.putObject(bucketName, key, new ByteArrayInputStream(content.getBytes()));
        ossClient.deleteObject(bucketName, key);

        // First data appending
        AppendObjectRequest appendObjectRequest = new AppendObjectRequest(bucketName, key,
                new ByteArrayInputStream(content.getBytes())).withPosition(0L);
        appendObjectRequest.setInitCRC(0L); // because it's first append, the previous data is empty and thus CRC is 0.
        AppendObjectResult appendObjectResult = ossClient.appendObject(appendObjectRequest);

        // Second data appending
        appendObjectRequest = new AppendObjectRequest(bucketName, key,
                new ByteArrayInputStream(content.getBytes()));
        appendObjectRequest.setPosition(appendObjectResult.getNextPosition());
        appendObjectRequest.setInitCRC(appendObjectResult.getClientCRC());// the initCRC is the first's CRC.
        appendObjectResult = ossClient.appendObject(appendObjectRequest);

        ossClient.deleteObject(bucketName, key);

        // Upload with checkpoint, it supports CRC as well.
        UploadFileRequest uploadFileRequest = new UploadFileRequest(bucketName, key);
        // Sets the upload file with a local file.
        uploadFileRequest.setUploadFile(uploadFile);
        // Sets the concurrent task number to 5 (default is 1).
        uploadFileRequest.setTaskNum(5);
        // Sets the part size to 1MB (default is 100K)
        uploadFileRequest.setPartSize(1024 * 1024 * 1);
        // Enable checkpoint (by default is off for checkpoint enabled upload)
        uploadFileRequest.setEnableCheckpoint(true);

        ossClient.uploadFile(uploadFileRequest);

        // Download with CRC. Note that range download does not support CRC.
        OSSObject ossObject = ossClient.getObject(bucketName, key);
        Assert.assertNull(ossObject.getClientCRC());
        Assert.assertNotNull(ossObject.getServerCRC());

        InputStream stream = ossObject.getObjectContent();
        while (stream.read() != -1) {
        }
        stream.close();

        // Check if CRC is consistent.
        OSSUtils.checkChecksum(IOUtils.getCRCValue(stream), ossObject.getServerCRC(), ossObject.getRequestId());

        ossClient.deleteObject(bucketName, key);

        ossClient.shutdown();
    }
}
